// ==UserScript==
// @name         YTU校园网自动登录_配合Python
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  ytu自动登录，自动调节页面样式，前后端分离填写密码
// @author       TaylorAndTony
// @match        http://202.194.116.116/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=116.116
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @require      file:///D:\TamperMonkeyComm\YTU_Password.js
// @run-at document-start
// ==/UserScript==

const port = 9988;

var styleBase = `font-size: 14px; font-family: "misans semibold", "OPPOSans M", Arial, sans-serif;`;
var styleBegin = `background: #025aa9; color: #fff; height: 20px; border-radius: 0 10px 10px 0; ${styleBase}`;
var styleEnd = `${styleBase}`;

function log(s) {
    console.log("%c YTU auto   %c %s", styleBegin, styleEnd, s);
}

const sel = {
    byId: id => document.getElementById(id),
    byClass: className => document.getElementsByClassName(className),
    byTag: tagName => document.getElementsByTagName(tagName),
    byName: name => document.getElementsByName(name),
    byQuery: query => document.querySelector(query),
    byQueryAll: query => document.querySelectorAll(query),
}

/**
 * Run the given callback at specific url once, and make sure it successfully ran once.
 * @param {Function} callback the callback function
 * @param {Regex} urlRegex the url regex
 * @param {number} T the interval time
 * @returns null
 */
function runOnce(callback, urlRegex=/./gm, T=500) {
    function registerDiv(id) {
        let div = document.createElement('div');
        div.id = id;
        div.style.display = 'none';
        document.body.appendChild(div);
    }
    if (!urlRegex.test(window.location.href)) {
        return;
    }
    let uniqueId = 'run-once-' + new Date().getTime() + '-' + parseInt(Math.random() * 1000);
    let timer = setInterval(() => {
        if (document.getElementById(uniqueId)) {
            clearInterval(timer);
        }
        callback();
        registerDiv(uniqueId);
    }, T)
}

GM_addStyle(`
/* for the first, biggest title */
.my-big-title {
    font-weight: bold;
    font-size: 36px;
    background-image: linear-gradient(90deg, #F78F59, #D45F4C, #EB617C, #D44CC4, #C049F5);
    color: transparent;
    -webkit-background-clip: text;
    -moz-background-clip: text;
    -o-background-clip: text;
}

/* digits */
.my-digits {
    color: #ea5514;
    font-size: 30px;
    text-shadow: 0 0 3px #f091a0;
    font-family: misans, opposans, cursive, sans-serif;
    letter-spacing: 2px;
}

/* qr code */
.mouse-hover-qr {
    width: 160px;
    transition: all .5s;
}

.mouse-hover-qr:hover {
    width: 300px;
}

/* make main panel transparent */
.transparent-panel {
    background: rgba(255,255,255,0.6);
    backdrop-filter: blur(10px);
    animation: loop-fade 5s infinite;
}

@keyframes loop-fade {
    10% {
        background: rgba(255,255,255,0.6);
    }
    50% {
        background: rgba(224, 245, 255, 0.6);
    }
    100% {
        background: rgba(255,255,255,0.6);
    }
}

/* left ugly red fonts */
.left-ugly {
    color: #035baa;
    font-size: 18px;
    font-weight: bold;
}

.half-smooth {
    transition: all 0.5s ease-in-out;
}
`);

function makeRotate(element, T = 0.1) {
    let u = btoa(2143).replace(/=/gm, '') + parseInt(Math.random() * 1000);
    let s = document.createElement('style');
    s.innerHTML = `
        .super-rotate-${u} {
            animation: ro ${T}s linear infinite;
        }
        @keyframes ro{
            0% {
                    transform: rotate(0deg);
            }
            100% {
                    transform: rotate(360deg);
            }
        }
    `;
    document.body.appendChild(s);
    element.classList.add(`super-rotate-${u}`);
}

function makeFunnyWiggle(element, T = 0.5, pix = 30, rotate = 0) {
    let s = document.createElement('style');
    s.innerHTML = `
        .smooth {
            transition: all ${T}s ease-in-out;
        }
    `;
    document.body.appendChild(s);
    element.style.position = 'relative';
    element.classList.add('smooth');
    setInterval(function () {
        element.style.left = Math.random() * pix + 'px';
        element.style.top = Math.random() * pix + 'px';
        if (rotate !== 0) {
            let negative = Math.random() > 0.5 ? -1 : 1;
            element.style.transform = `rotate(${negative * Math.random() * rotate}deg)`;
        }
    }, T * 500);
}

function makeBigWhenHover(element, scale = 2, T = 0.5, enlargeFont = false) {
    // element.classList.add('mouse-hover-scale');
    element.style.transition = `all ${T}s ease-in-out`;
    let originFontSize = element.style.fontSize;
    element.addEventListener('mouseover', function () {
        element.style.transform = `scale(${scale})`;
        if (enlargeFont) element.style.fontSize = '48px';
    });
    element.addEventListener('mouseout', function () {
        element.style.transform = `scale(1)`;
        element.style.fontSize = originFontSize;
    });
}

/**
 * change the style of login success page, and some text
 * this will continue to run until modified.
 * Configure what to modify at the end of this function
 */
function showLoginSuccess() {
    const changeTitle = () => {
        // change title
        let title = sel.byQuery('#login-form > h2');
        title.innerHTML = '自动登录成功';
        title.classList.add('my-big-title');
        makeBigWhenHover(title);
        makeFunnyWiggle(title, 0.5, 30, 0);
    };
    const changeUsed = () => {
        // change used total amount
        let used = sel.byQuery('#used_flow');
        used.classList.add('my-digits');
        makeBigWhenHover(used, undefined, undefined, true);
    };
    const convertUnit = () => {
        // use GB not MB
        let used = sel.byQuery('#used_flow');
        if (used.innerText.includes("M")) {
            let digit = /\d+/.exec(used.innerText)[0];
            let gb = parseInt(digit) * 0.001;
            let s = gb.toFixed(1) + " GB";
            used.innerText = s;
        }
    };
    const highlight = () => {
        // highlight the balance
        let balance = sel.byQuery('#balance');
        balance.classList.add('my-digits');
        balance.style.cssText += `cursor: pointer;`;
        makeBigWhenHover(balance, undefined, undefined, true);
        balance.onclick = function () {
            balance.innerText = '9999999.00';
        }
    };

    const noRedColor = () => {
        // left ugly text
        // change red text to YTU blue
        sel.byQueryAll('span').forEach(i => {
            // match red color
            if (['rgb(255, 0, 0)', 'red', '#f00', '#ff0000'].includes(i.style.color)) {
                i.style.cssText = '';
                i.classList.add('left-ugly');
            }
        });
    };
    const addText = () => {
        // add some text saying that this is so ugly
        let html = `
            <p style="margin-top:5px;margin-right:0;margin-bottom:5px;margin-left: 0">
                <span style="font-family: Arial, sans-serif">6. </span>
                <strong>
                    <span style="font-family:宋体">【页面说明】</span>
                </strong>
                这个 YTU 登录页面左侧实在是<strong>太丑了</strong>，而且这个页面没有<strong>动感</strong>，我很烦，帮你改了。
            </p>
        `;
        sel.byQuery('#notice-content > p:nth-child(7)').insertAdjacentHTML('afterend', html);
    };
    const centerQrCode = () => {
        // center the QR code
        sel.byQuery('#notice-content > p:nth-child(5)').style.textAlign = 'center';
        let qr = sel.byQuery('#notice-content > p:nth-child(5) > img')
        qr.classList.add('mouse-hover-qr');
        makeFunnyWiggle(qr, 0.5, 30, 10);
    };
    const refineLeftIcon = () => {
        // remove a strange icon
        sel.byQuery('div.col-md-6.col-sm-6.hidden-xs.notice > div.pull-right.middle-right > img').remove();
    };
    const rotateLogo = () => {
        // make YTU logo rotating!
        let logo = sel.byQuery('body > div.navbar.navbar-static-top.nav-portal > div > div > img');
        let logoWrapper = sel.byQuery('body > div.navbar.navbar-static-top.nav-portal > div > div');
        makeBigWhenHover(logoWrapper, 4, 2);
        makeRotate(logo, 2);
    };
    const rotateButtons = () => {
        // make 自助服务 rotating and scale up
        let selfServiceBtn = sel.byQuery('#self-service');
        let selfServiceBtnWrapper = sel.byQuery('#login-form > div > div:nth-child(2)');
        selfServiceBtn.classList.add('half-smooth');
        makeBigWhenHover(selfServiceBtn);
        makeBigWhenHover(selfServiceBtnWrapper);
        makeRotate(selfServiceBtn, 1);
    };
    const callbacks = [
        changeTitle,
        changeUsed,
        convertUnit,
        highlight,
        noRedColor,
        addText,
        centerQrCode,
        refineLeftIcon,
        rotateLogo,
        rotateButtons,
    ];
    callbacks.forEach(i => runOnce(i));
}


function makePanelTransparent() {
    let p = sel.byQuery('body > div.container.login');
    if (p) {
        // p.style.cssText = `
        // background: rgba(255,255,255,0.6);
        // backdrop-filter: blur(10px);
        // `;
        p.classList.add('transparent-panel');
    } else {
        log('Panel not found');
    }
}


/**
 * Auto login
 */
function getLoginInfo() {
    let timer = setInterval(() => {
        // wrong login page
        if (document.body.innerHTML.includes('当前设备不在线')) {
            document.location.href = 'http://202.194.116.116/';
        }
        // already logged in
        if (document.getElementById('logout') != null) {
            log('Login finished successfully');
            showLoginSuccess();
            clearInterval(timer);
            return;
        }
        // first try local js file
        try {
            let data = getResponse()
            sel.byId('username').value = data.username;
            sel.byId('password').value = data.password;
            sel.byId('login').click();
            log("[file] Read success!");
            clearInterval(timer);
            return;
        } catch (e) {
            log("[file] no password js file loaded");
        }
        // otherwise, use fetch password
        GM_xmlhttpRequest({
            method: 'GET',
            url: 'http://localhost:' + port,
            // success
            onload: function (response) {
                let data = JSON.parse(response.responseText);
                log(data);
                try {
                    // update password
                    sel.byId('username').value = data.username;
                    sel.byId('password').value = data.password;
                    sel.byId('login').click();
                    clearInterval(timer);
                    log('[xml] Timer clear');
                } catch (e) {
                    log('[xml] Not at login page!');
                }
            },
            // error
            ontimeout: function () {
                log('[xml] Timeout');
            },
            onerror: function () {
                log('[xml] Error');
            }
        });
    }, 1000)
}

(function () {
    'use strict';
    makePanelTransparent();
    getLoginInfo();
    // Your code here...
})();